﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;

namespace ArivisTests.Models
{
    /// <summary>
    /// Base class for all test items
    /// </summary>
    public abstract class TestItem : IEquatable<TestItem>, IComparable<TestItem>
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }
        
        public override string ToString()
        {
            return this.Name;
        }

        public bool Equals(TestItem other)
        {
            return (other == null) ? false : (this.Id == other.Id);
        }

        public int CompareTo(TestItem other)
        {
            return (other == null) ? this.Name.CompareTo(null) : this.Name.CompareTo(other.Name);
        }
    }


    /// <summary>
    /// Description of a test
    /// </summary>
    [Table("TestScenario")]
    public class TestScenario : TestItem
    {
        [DataType(DataType.Url)]
        public string Url { get; set; }

        [DataType(DataType.Url)]
        public string TicketUrl { get; set; }

        public int Duration { get; set; }

        public virtual UserProfile Owner { get; set; }

        public virtual ICollection<TestPlan> Plans { get; set; }

        public virtual ICollection<TestCase> Cases { get; set; }
    }

    /// <summary>
    /// Predefined set of tests
    /// </summary>
    [Table("TestPlan")]
    public class TestPlan : TestItem
    {
        public virtual ICollection<TestScenario> Tests { get; set; }
    }

    /// <summary>
    /// A Test scenario that is executed as part of a test run
    /// </summary>
    [Table("TestCase")]
    public class TestCase : TestItem
    {
        public static TestCase Create(ArivisTestsDBContext context, TestScenario scenario)
        {
            TestCase testCase = context.TestCases.Create();
            testCase.Name = scenario.Name;
            testCase.Scenario = scenario;
            return testCase;
        }

        /// <summary>
        /// The test scenario that describes the test case
        /// </summary>
        public virtual TestScenario Scenario { get; set; }

        /// <summary>
        /// The user that should run this test case
        /// </summary>
        [Display(Name="Tester")]
        public virtual UserProfile User { get; set; }

        /// <summary>
        /// The test result
        /// </summary>
        public virtual TestResult Result { get; set; }

        /// <summary>
        /// A comment provided by the tester
        /// </summary>
        [DataType(DataType.MultilineText)]
        public string Comment { get; set; }

        /// <summary>
        /// Any Tickets related to this test
        /// </summary>
        [DataType(DataType.MultilineText)]
        public string Tickets { get; set; }

        /// <summary>
        /// The test run for this test
        /// </summary>
        public virtual TestRun Run { get; set; }

        public int Order { get; set; }
    }

    /// <summary>
    /// A Test Run created from a Test Plan or individual Test Scenarios
    /// </summary>
    [Table("TestRun")]
    public class TestRun : TestItem
    {
        [Required]
        [DisplayFormat(DataFormatString="{0:d}")]
        public DateTime Date { get; set; }

        public bool Active { get; set; }

        public virtual ICollection<TestCase> Tests { get; set; }

        [NotMapped]
        public string Progress
        {
            get
            {
                int count = this.Tests.Count();
                int done = this.Tests.Count(testCase => testCase.Result != null);
                float percent = (count == 0) ? 1f : (float)done / (float)count;
                return string.Format("{0:p} ({1} / {2})", percent, done, count);
            }
        }

        [NotMapped]
        public string Results
        {
            get
            {
                var resultGroups = Tests.GroupBy(x => x.Result).OrderBy(x => x.Key).ToList();
                var sb = new System.Text.StringBuilder();
                bool first = true;
                foreach (var resultGroup in resultGroups)
                {
                    if (resultGroup.Key == null) continue;
                    if (first) first = false; else sb.Append(", ");
                    sb.Append(resultGroup.Key.Name);
                    sb.Append(": ");
                    sb.Append(resultGroup.Count());
                }
                return sb.ToString();
            }
        }
    }

    [Table("TestResult")]
    public class TestResult : TestItem
    {
        // a custom HTML color
        public string Color { get; set; }
    }
}